{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from neo4j.v1 import GraphDatabase\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "driver = GraphDatabase.driver('bolt://localhost:7687',auth=('neo4j', 'password'))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_results(array):\n",
    "    a = np.array(array)\n",
    "    print('Average response: {}ms'.format(a.mean()))\n",
    "    print('Max response: {}ms'.format(max(a)))\n",
    "    print('Min response: {}ms'.format(min(a)))\n",
    "    for p in [25,50,75,90,95,99]:\n",
    "        print('{}th percentile: {}ms'.format(p, np.percentile(a,p)))\n",
    "        \n",
    "def test_query(query):\n",
    "    session = driver.session()\n",
    "    results = []\n",
    "    for _ in range(1000):\n",
    "        r = session.run(query)\n",
    "        summary = r.summary()\n",
    "        millis = summary.result_available_after + summary.result_consumed_after\n",
    "        results.append(millis)\n",
    "    session.close()\n",
    "    print_results(results)\n",
    "    \n",
    "def import_query(query):\n",
    "    with driver.session() as session:\n",
    "        session.run(query)\n",
    "        session.run(\"call apoc.warmup.run()\")\n",
    "\n",
    "def delete_db_query():\n",
    "    delete_query = \"\"\"\n",
    "    CALL apoc.periodic.commit('MATCH (n) WITH n limit $limit \n",
    "                           DETACH DELETE n RETURN count(*)', \n",
    "                          {limit:100000})\n",
    "    \"\"\"\n",
    "    with driver.session() as session:\n",
    "        session.run(delete_query)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# First example with reaction type as attribute"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import_as_attribute = \"\"\"\n",
    "\n",
    "CALL apoc.periodic.iterate(\n",
    "  \"UNWIND range(0,100) as i\n",
    "   return i\",\n",
    "  \"CREATE (post:Post{id:i})\n",
    "   WITH i,post\n",
    "   UNWIND range (0,10000) as j\n",
    "   WITH i,j,post, CASE j%6 WHEN 0 THEN 'like'\n",
    "                           WHEN 1 THEN 'love'\n",
    "                           WHEN 2 THEN 'haha'\n",
    "                           WHEN 3 THEN 'wow'\n",
    "                           WHEN 4 THEN 'sad'\n",
    "                           WHEN 5 THEN 'angry' END as reaction\n",
    "   CREATE (post)<-[:REACTION{type:reaction}]-(:User)\",\n",
    "  {parallel:True})\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "import_query(import_as_attribute)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 799.739ms\n",
      "Max response: 1860ms\n",
      "Min response: 768ms\n",
      "25th percentile: 783.0ms\n",
      "50th percentile: 787.0ms\n",
      "75th percentile: 792.0ms\n",
      "90th percentile: 806.0ms\n",
      "95th percentile: 860.0999999999999ms\n",
      "99th percentile: 1071.03ms\n"
     ]
    }
   ],
   "source": [
    "attribute_first_query = \"\"\"\n",
    "MATCH (p:Post)<-[rel]-()\n",
    "RETURN p.id as id, rel.type as type, count(*) AS count\n",
    "ORDER by count DESC limit 5\n",
    "\"\"\"\n",
    "test_query(attribute_first_query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 657.88ms\n",
      "Max response: 908ms\n",
      "Min response: 644ms\n",
      "25th percentile: 650.0ms\n",
      "50th percentile: 653.0ms\n",
      "75th percentile: 657.0ms\n",
      "90th percentile: 667.0ms\n",
      "95th percentile: 687.0ms\n",
      "99th percentile: 760.1099999999999ms\n"
     ]
    }
   ],
   "source": [
    "attribute_second_query = \"\"\"\n",
    "MATCH (p:Post)<-[rel]-()\n",
    "WITH p, rel.type as type, count(*) AS count\n",
    "ORDER by count DESC limit 5\n",
    "RETURN p.id,type,count\n",
    "\n",
    "\"\"\"\n",
    "test_query(attribute_second_query)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Second example with reaction type as node label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "delete_db_query()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import_as_node_label = \"\"\"\n",
    "CALL apoc.periodic.iterate(\n",
    "  \"UNWIND range(0,100) as i\n",
    "   return i\",\n",
    "  \"CREATE (post:Post{id:i})\n",
    "   with i,post\n",
    "   UNWIND range(0,10000) as j\n",
    "   WITH i,post, CASE j%6 WHEN 0 THEN 'like'\n",
    "   WHEN 1 THEN 'love'\n",
    "   WHEN 2 THEN 'haha'\n",
    "   WHEN 3 THEN 'wow'\n",
    "   WHEN 4 THEN 'sad'\n",
    "   WHEN 5 THEN 'angry' END as reaction\n",
    "   // Create node with a dynamic label\n",
    "   call apoc.create.node([reaction], {}) yield node\n",
    "   CREATE (post)<-[:TO]-(node)\n",
    "   CREATE (node)<-[:REACTION]-(:User)\",\n",
    "  {parallel:True})\n",
    "\"\"\"\n",
    "import_query(import_as_node_label)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 569.038ms\n",
      "Max response: 1255ms\n",
      "Min response: 548ms\n",
      "25th percentile: 553.0ms\n",
      "50th percentile: 556.0ms\n",
      "75th percentile: 560.0ms\n",
      "90th percentile: 570.1ms\n",
      "95th percentile: 637.0999999999999ms\n",
      "99th percentile: 903.3099999999997ms\n"
     ]
    }
   ],
   "source": [
    "label_query = \"\"\"\n",
    "MATCH (p:Post)<--(reaction)\n",
    "WITH p,labels(reaction) as labels,count(*) as count\n",
    "ORDER BY count DESC LIMIT 5\n",
    "RETURN p.id as id,labels[0] as type,count(*)\n",
    "\n",
    "\"\"\"\n",
    "test_query(label_query)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Third example with reaction type as relationship type"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "delete_db_query()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "import_type_as_rel_type = \"\"\"\n",
    "CALL apoc.periodic.iterate(\n",
    "  \"UNWIND range(0,100) as i\n",
    "   return i\",\n",
    "  \"CREATE (post:Post{id:i})\n",
    "   with i,post\n",
    "   UNWIND range(0,10000) as j\n",
    "   CREATE (u:User)\n",
    "   WITH i,post,u, CASE j%6 WHEN 0 THEN 'like'\n",
    "                           WHEN 1 THEN 'love'\n",
    "                           WHEN 2 THEN 'haha'\n",
    "                           WHEN 3 THEN 'wow'\n",
    "                           WHEN 4 THEN 'sad'\n",
    "                           WHEN 5 THEN 'angry' END as reaction\n",
    "  // Create relationship with a dynamic type\n",
    "  CALL apoc.create.relationship(u, reaction, {}, post) YIELD rel\n",
    "  RETURN count(*)\",\n",
    "  {parallel:True})\n",
    "\"\"\"\n",
    "import_query(import_type_as_rel_type)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 629.604ms\n",
      "Max response: 903ms\n",
      "Min response: 607ms\n",
      "25th percentile: 616.0ms\n",
      "50th percentile: 628.0ms\n",
      "75th percentile: 635.0ms\n",
      "90th percentile: 648.1ms\n",
      "95th percentile: 656.0ms\n",
      "99th percentile: 698.0699999999999ms\n"
     ]
    }
   ],
   "source": [
    "rel_type_first_query = \"\"\"\n",
    "MATCH (p:Post)<-[rel]-()\n",
    "WITH p,type(rel) as type,count(*) as count\n",
    "ORDER BY count DESC limit 5 \n",
    "RETURN p.id as id,type,count\n",
    "\n",
    "\"\"\"\n",
    "test_query(rel_type_first_query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 0.998ms\n",
      "Max response: 82ms\n",
      "Min response: 0ms\n",
      "25th percentile: 1.0ms\n",
      "50th percentile: 1.0ms\n",
      "75th percentile: 1.0ms\n",
      "90th percentile: 1.0ms\n",
      "95th percentile: 2.0ms\n",
      "99th percentile: 2.0ms\n"
     ]
    }
   ],
   "source": [
    "rel_type_second_query = \"\"\"\n",
    "MATCH (p:Post)\n",
    "WITH p\n",
    "UNWIND [{key:'like',count:size((p)<-[:like]-())},\n",
    "        {key:'love',count:size((p)<-[:love]-())},\n",
    "        {key:'haha',count:size((p)<-[:haha]-())},\n",
    "        {key:'wow', count: size((p)<-[:wow]-())},\n",
    "        {key:'sad', count: size((p)<-[:sad]-())},\n",
    "        {key:'angry',count: size((p)<-[:angry]-())}] as k\n",
    "WITH p,k.key as key,k.count as count\n",
    "ORDER BY count DESC LIMIT 5\n",
    "RETURN p.id as id,key,count\n",
    "\n",
    "\"\"\"\n",
    "test_query(rel_type_second_query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Average response: 1.869ms\n",
      "Max response: 74ms\n",
      "Min response: 1ms\n",
      "25th percentile: 1.0ms\n",
      "50th percentile: 2.0ms\n",
      "75th percentile: 2.0ms\n",
      "90th percentile: 3.0ms\n",
      "95th percentile: 3.0ms\n",
      "99th percentile: 4.0ms\n"
     ]
    }
   ],
   "source": [
    "rel_type_apoc_query = \"\"\"\n",
    "\n",
    "MATCH (p:Post)\n",
    "UNWIND apoc.node.relationship.types(p) as type\n",
    "WITH p, type, apoc.node.degree.in(p, type) as count\n",
    "ORDER BY count DESC LIMIT 5\n",
    "RETURN p.id as post, type, count\n",
    "\n",
    "\"\"\"\n",
    "test_query(rel_type_apoc_query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
